﻿#region Copyright Notice
// This file is part of GPL-It.
// Copyright (C) 2008 Fabien Barbier
// 
// GPL-It is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// GPL-It is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
#endregion

using System;
using System.IO;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace GPL_It
{
	partial class MainForm : Form
	{
		Dictionary<string, int> extensionDictionary = new Dictionary<string,int>();
		NoticeGenerationForm noticeGenerationForm;

		#region Constructor & Initialization

		public MainForm()
		{
			InitializeComponent();
			LoadResources();
			LoadSettings();
			EnableProgression(false);
		}

		private void LoadResources()
		{
			openFileDialog.Filter = Properties.Resources.TextFileFilter;
			saveFileDialog.Filter = Properties.Resources.TextFileFilter;
		}

		#endregion

		#region Settings Management

		private void LoadSettings()
		{
			StringCollection extensions = Properties.Settings.Default.Extensions;

			for (int i = 0; i < extensions.Count; i++)
			{
				string extension = extensions[i];

				if (IsExtensionValid(extension))
				{
					extensionListBox.Items.Add(extension);
					extensionDictionary.Add(extension, i);
				}
				else
				{
					extensions.RemoveAt(i);
					i--;
				}
			}

			if (Directory.Exists(Properties.Settings.Default.ProjectPath))
				pathTextBox.Text = Properties.Settings.Default.ProjectPath;
			headerTextBox.Text = Properties.Settings.Default.ProjectNotice;
		}

		private void SaveSettings()
		{
			StringCollection extensions = new StringCollection();

			foreach (string extension in extensionDictionary.Keys)
				extensions.Add(extension);
			Properties.Settings.Default.Extensions = extensions;
			Properties.Settings.Default.ProjectPath = pathTextBox.Text;
			Properties.Settings.Default.ProjectNotice = headerTextBox.Text;
			Properties.Settings.Default.Save();
		}

		#endregion

		private void EnableProgression(bool enable)
		{
			progressionLabel.Enabled = enable;
			progressBar.Enabled = enable;
			fileInformationLabel.Enabled = enable;
			runButton.Enabled = !enable;
			projectGroupBox.Enabled = !enable;
			extensionsGroupBox.Enabled = !enable;
			headerGroupBox.Enabled = !enable;
			if (!enable)
			{
				fileInformationLabel.Text = string.Empty;
				progressBar.Value = 0;
			}
		}

		private static bool IsExtensionValid(string extension)
		{
			// Allowed characters: a-z, A-Z, 0-9, _
			// Maximum allowed length: 5
			// Minimum allowed length: 1

			if (extension == null || extension.Length < 0 || extension.Length > 5)
				return false;

			// Check each characater in the string using rules explained above
			foreach (char c in extension)
			{
				if ((c < 'a' || c > 'z') &&
					(c < 'A' || c > 'Z') &&
					(c < '0' || c > '9') &&
					c != '_')
					return false;
			}

			return true;
		}

		private string BuildExtensionFilter()
		{
			StringBuilder filter = new StringBuilder();

			foreach (string extension in extensionDictionary.Keys)
			{
				filter.Append("*.");
				filter.Append(extension);
				filter.Append(";");
			}

			if (filter.Length > 0)
				filter.Length--; // Remove the last added semicolon

			return filter.ToString();
		}

		private string FormatMessage(string messageFormat, params object[] args)
		{
			return string.Format(Properties.Resources.Culture, messageFormat, args);
		}

		private void ErrorMessage(string text)
		{
			MessageBox.Show(this, text, Properties.Resources.ErrorMessageBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
		}

		private void ErrorMessage(string format, params object[] args)
		{
			MessageBox.Show(this, FormatMessage(format, args), Properties.Resources.ErrorMessageBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
		}

		public string HeaderText
		{
			get
			{
				return headerTextBox.Text;
			}
			set
			{
				headerTextBox.Text = value;
			}
		}

		private NoticeGenerationForm NoticeGenerationForm
		{
			get
			{
				if (noticeGenerationForm == null)
					noticeGenerationForm = new NoticeGenerationForm(this);
				return noticeGenerationForm;
			}
		}

		private void browseButton_Click(object sender, EventArgs e)
		{
			if (Directory.Exists(pathTextBox.Text))
				folderBrowserDialog.SelectedPath = pathTextBox.Text;
			else
				folderBrowserDialog.SelectedPath = string.Empty;

			if (folderBrowserDialog.ShowDialog(this) == DialogResult.OK)
				pathTextBox.Text = folderBrowserDialog.SelectedPath;
		}

		private void extensionListBox_SelectedIndexChanged(object sender, EventArgs e)
		{
			extensionTextBox.Text = (string)extensionListBox.SelectedItem;
		}

		private void addExtensionButton_Click(object sender, EventArgs e)
		{
			string extension = extensionTextBox.Text;

			if (!IsExtensionValid(extension))
			{
				ErrorMessage(Properties.Resources.InvalidExtensionErrorMessage, extension);
				return;
			}

			if (!extensionDictionary.ContainsKey(extension))
			{
				extensionDictionary.Add(extension, extensionListBox.Items.Count);
				extensionListBox.Items.Add(extension);
			}
		}

		private void removeExtensionButton_Click(object sender, EventArgs e)
		{
			string extension = extensionTextBox.Text;
			int index;

			if (extensionDictionary.TryGetValue(extension, out index))
			{
				extensionListBox.Items.RemoveAt(index);
				extensionDictionary.Remove(extension);
			}
		}

		protected override void OnFormClosed(FormClosedEventArgs e)
		{
			SaveSettings();
			base.OnFormClosed(e);
		}

		private void loadHeaderButton_Click(object sender, EventArgs e)
		{
			if (openFileDialog.ShowDialog() == DialogResult.OK)
				headerTextBox.Text = File.ReadAllText(openFileDialog.FileName, Encoding.UTF8);
		}

		private void saveHeaderButton_Click(object sender, EventArgs e)
		{
			if (saveFileDialog.ShowDialog() == DialogResult.OK)
				File.WriteAllText(saveFileDialog.FileName, headerTextBox.Text, Encoding.UTF8);
		}

		private void copyHeaderButton_Click(object sender, EventArgs e)
		{
			Clipboard.Clear();
			if (headerTextBox.Text.Length > 0)
				Clipboard.SetText(headerTextBox.Text, TextDataFormat.UnicodeText);
		}

		private void generateHeaderButton_Click(object sender, EventArgs e)
		{
			NoticeGenerationForm.ShowDialog(this);
		}

		private void runButton_Click(object sender, EventArgs e)
		{
			DirectoryInfo projectDirectory;
			string header;

			try { projectDirectory = new DirectoryInfo(pathTextBox.Text); }
			catch (Exception ex)
			{
				ErrorMessage(ex.Message);
				return;
			}

			if (!Directory.Exists(pathTextBox.Text))
			{
				ErrorMessage(Properties.Resources.InvalidPathErrorMessage, pathTextBox.Text);
				return;
			}

			EnableProgression(true);

			header = headerTextBox.Text;

			FileInfo[] files = projectDirectory.GetFiles(BuildExtensionFilter(), SearchOption.AllDirectories);
			string informationMessageFormat = Properties.Resources.FileInformationMessage;

			for (int i = 0; i < files.Length; i++)
			{
				FileInfo file;
				FileStream fileStream;
				StreamReader reader;
				StreamWriter writer;
				string text;

				file = files[i];
				fileStream = file.Open(FileMode.Open, FileAccess.Read | FileAccess.Write, FileShare.None);
				reader = new StreamReader(fileStream, true);
				fileInformationLabel.Text = FormatMessage(informationMessageFormat, i + 1, files.Length, file.Name);
				text = reader.ReadToEnd();
				fileStream.Seek(0, SeekOrigin.Begin);
				fileStream.SetLength(0);
				writer = new StreamWriter(fileStream, reader.CurrentEncoding);
				writer.WriteLine(header);
				writer.Write(text);
				// Dispose order is very important here !
				writer.Dispose();
				reader.Dispose();
				fileStream.Dispose();
				Application.DoEvents();
			}
			EnableProgression(false);
		}
	}
}
